require 'digest/sha1'

class User < ActiveRecord::Base
  has_many :user_roles

  # Max & min lengths for all fields
  NAME_MIN_LENGTH = 4
  NAME_MAX_LENGTH = 20
  PASSWORD_MIN_LENGTH = 6
  PASSWORD_MAX_LENGTH = 40
  EMAIL_MAX_LENGTH = 50
  NAME_RANGE = NAME_MIN_LENGTH..NAME_MAX_LENGTH
  PASSWORD_RANGE = PASSWORD_MIN_LENGTH..PASSWORD_MAX_LENGTH

  # Text box sizes for display in the views
  NAME_SIZE = 30
  PASSWORD_SIZE = 30
  EMAIL_SIZE = 30

  # Validation 
  validates_presence_of :email
  validates_uniqueness_of :email
  validates_format_of :email, 
    :with => /^[A-Z0-9._%-]+@([A-Z0-9-]+\.)+[A-Z]{2,4}$/i, 
    :message => "must be a valid email address"
  validates_length_of :email, :maximum => EMAIL_MAX_LENGTH 

  validates_length_of :first_name, :within => NAME_RANGE
  validates_format_of :first_name, 
    :with => /^[A-Z]*$/i,
    :message => "must contain only letters"

  validates_length_of :family_name, :within =>NAME_RANGE
  validates_format_of :family_name, 
    :with => /^[A-Z]*$/i,
    :message => "must contain only letters"
  
  validates_length_of :password, :within => PASSWORD_RANGE, :on => :create 
  validates_length_of :password, :within => PASSWORD_RANGE, :on => :update, :allow_nil => true 
  validates_confirmation_of :password 

  def validate
    errors.add_to_base("Missing password" ) if hashed_password.blank?
  end
  
  # Attributes
  attr_accessor :password_confirmation
  attr_accessor :remember_me
    
  def password
    @password
  end

  def password=(pwd)
    @password = pwd
    return if pwd.blank?
    create_new_salt
    self.hashed_password = User.encrypted_password(self.password, self.salt)
  end

  def User.authenticate(email, password)
    actual_user = User.find_by_email(email)
    if actual_user
      expected_password = User.encrypted_password(password, actual_user.salt)
      if actual_user.hashed_password != expected_password
        nil
      else
        actual_user
      end
    end
  end

  def login!(session)
    session[:user_id] = self.id
  end

  def logout!(session, cookies)
    session[:user_id] = nil
    cookies.delete(:authorization_token)
  end   
  
  def remember!(cookies)
    cookies[:remember_me] = { :value => "1", :expires => 10.years.from_now }
    self.authorization_token = get_authorization_token
    save!
    cookies[:authorization_token] = {:value => self.authorization_token, :expires => 10.years.from_now } 
  end

  def forget!(cookies)
    cookies.delete(:remember_me)
    cookies.delete(:authorization_token)
  end

  def copy_transient_fields(user)
    self.remember_me = user.remember_me
  end

 private

  def get_authorization_token
    Digest::SHA1.hexdigest("#{self.email}:#{self.password}:#{self.salt}")
  end   

  def self.encrypted_password(password, salt)
    string_to_hash = password + "wibble" + salt # 'wibble' makes it harder to guess
    Digest::SHA1.hexdigest(string_to_hash)
  end

  def create_new_salt
    self.salt = self.object_id.to_s + rand.to_s
  end
  
end
